#ifndef UL_RINGBUFFER_H
#define UL_RINGBUFFER_H

#include "ul_config.h"
#include "ul_list.h"

#ifdef __cplusplus
extern "C" {
#endif
    
/*
 * ringbuffer structure
 */
struct ul_ringbuffer
{
    ul_uint8_t *buffer_ptr;
    
    ul_uint16_t read_mirror : 1;
    ul_uint16_t read_index : 15;
    ul_uint16_t write_mirror : 1;
    ul_uint16_t write_index : 15;
    
    ul_int16_t buffer_size;
};

/* Define block header structure */
struct ul_block_info {
    ul_uint8_t block_size;
    ul_list_t node;
};

struct ul_ringblock
{
    struct ul_ringbuffer *ringbuffer;
};

enum ul_ringbuffer_state
{
    UL_RINGBUFFER_EMPTY,
    UL_RINGBUFFER_FULL,
    /* half full is neither full nor empty */
    UL_RINGBUFFER_HALFFULL,
};

/*
 * ringbuffer interface
 */
void ul_ringbuffer_init(struct ul_ringbuffer *rb, ul_uint8_t *pool, ul_int16_t size);
void ul_ringbuffer_reset(struct ul_ringbuffer *rb);
ul_size_t ul_ringbuffer_put(struct ul_ringbuffer *rb, const ul_uint8_t *ptr, ul_uint16_t length);
ul_size_t ul_ringbuffer_put_force(struct ul_ringbuffer *rb, const ul_uint8_t *ptr, ul_uint16_t length);
ul_size_t ul_ringbuffer_putchar(struct ul_ringbuffer *rb, const ul_uint8_t ch);
ul_size_t ul_ringbuffer_putchar_force(struct ul_ringbuffer *rb, const ul_uint8_t ch);
ul_size_t ul_ringbuffer_get(struct ul_ringbuffer *rb, ul_uint8_t *ptr, ul_uint16_t length);
ul_size_t ul_ringbuffer_peek(struct ul_ringbuffer *rb, ul_uint8_t **ptr);
ul_size_t ul_ringbuffer_getchar(struct ul_ringbuffer *rb, ul_uint8_t *ch);
ul_size_t ul_ringbuffer_data_len(struct ul_ringbuffer *rb);

struct ul_ringbuffer* ul_ringbuffer_create(ul_uint16_t length);
void ul_ringbuffer_destroy(struct ul_ringbuffer *rb);


/**
 * @brief Get the buffer size of the ring buffer object.
 *
 * @param rb        A pointer to the ring buffer object.
 *
 * @return  Buffer size.
 */
ul_inline ul_uint16_t ul_ringbuffer_get_size(struct ul_ringbuffer *rb)
{
    UL_ASSERT(rb != UL_NULL);
    return rb->buffer_size;
}

/** return the size of empty space in rb */
#define ul_ringbuffer_space_len(rb) ((rb)->buffer_size - ul_ringbuffer_data_len(rb))


#ifdef __cplusplus
}
#endif

#endif  /* UL_RINGBUFFER_H */
